﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Collections.Specialized;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace CommunicationPrototypeServer
{
    class C2DM
    {
        // Hardcoded for now
        //private const string RegistrationId = "APA91bGeekiTiOQzBZESV6jToHivo8EaMIqhuZrij7XhgPY3mul8L50VV_NUwUI_0UzdaFMlzjqYhbeGaBVZwQrTzNA_BwFuBMTTbkF64w2_LOYh5fvcoMqLKaDcSrhpYSLIjpxIMG664Dn8T5yCc4hV6smf2lKmFQ";
        private const string RegistrationId = "APA91bGiEGHkKbJkGmVnFQAOjwWfeThQfVvL0EWYgFzF2xZRCZHEY0lepRmY4Mom40N1jPBXuwxuScorBUzSB1X4p-1X4C0e4juBdEs82WaeGezESG3BizSsbfIg-lvvaThcGZ1KBZL-1ugAz2bpQ2nGx3JN-k1MVg";
       
        private const string GoogleAuthUrl = "https://www.google.com/accounts/ClientLogin";
        // TODO : Production code should use https (secure) push and have the correct certificate
        private const string GoogleMessageUrl = "http://android.clients.google.com/c2dm/send";

        private const string PostWebRequest = "POST";
        private const string AuthTokenHeader = "Auth=";
        private const string UpdateClientAuth = "Update-Client-Auth";

        // Post data parameters
        private const string RegistrationIdParam = "registration_id";
        private const string CollapseKeyParam = "collapse_key";
        private const string DataPayloadParam = "data.payload";
        private const string DelayWhileIdleParam = "delay_while_idle";

        private string _authTokenString = String.Empty;
        private string _updatedAuthTokenString = String.Empty;
        private string _message = String.Empty;

        public void StartServer()
        {
            if ((_authTokenString = GetAuthentificationToken()).Equals(String.Empty))
            {
                Console.ReadLine();
                return;
            }

            while (true)
            {
                try
                {
                    Console.Write("Message> ");
                    _message = Console.ReadLine().ToLower().Trim();
                    SendMessage(_authTokenString, RegistrationId, _message);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    Console.WriteLine(ex.StackTrace);
                }
            }
        }

        private static string GetAuthentificationToken()
        {
            string authTokenString = String.Empty;
            try
            {
                WebRequest request = WebRequest.Create(GoogleAuthUrl);
                request.Method = PostWebRequest;

                NameValueCollection postFieldNameValue = new NameValueCollection();
                postFieldNameValue.Add("Email", " mobilesales88@gmail.com");
                postFieldNameValue.Add("Passwd", "Inzynierka2011");
                postFieldNameValue.Add("accountType", "GOOGLE");
                postFieldNameValue.Add("source", "Google-cURL-Example");
                postFieldNameValue.Add("service", "ac2dm");

                string postData = GetPostStringFrom(postFieldNameValue);
                byte[] byteArray = Encoding.UTF8.GetBytes(postData);

                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = byteArray.Length;

                Stream dataStream = request.GetRequestStream();
                dataStream.Write(byteArray, 0, byteArray.Length);
                dataStream.Close();

                WebResponse response = request.GetResponse();
                if (((HttpWebResponse)response).StatusCode.Equals(HttpStatusCode.OK))
                {
                    dataStream = response.GetResponseStream();
                    StreamReader reader = new StreamReader(dataStream);

                    string responseFromServer = reader.ReadToEnd();

                    authTokenString = ParseForAuthTokenKey(responseFromServer);

                    reader.Close();
                    dataStream.Close();
                }
                else
                {
                    Console.WriteLine("Response from web service not OK :");
                    Console.WriteLine(((HttpWebResponse)response).StatusDescription);
                }

                response.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Getting Authentication Failure");
                Console.WriteLine(ex.Message);
            }
            return authTokenString;
        }

        private static void SendMessage(string authTokenString, string registrationId, string message)
        {
            //Certeficate was not being accepted for the sercure call
            //ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(GoogleMessageUrl);
            request.Method = PostWebRequest;
            request.KeepAlive = false;

            NameValueCollection postFieldNameValue = new NameValueCollection();
            postFieldNameValue.Add(RegistrationIdParam, registrationId);
            postFieldNameValue.Add(CollapseKeyParam, "0");
            postFieldNameValue.Add(DelayWhileIdleParam, "0");
            postFieldNameValue.Add(DataPayloadParam, message);

            string postData = GetPostStringFrom(postFieldNameValue);
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);

            request.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
            request.ContentLength = byteArray.Length;

            request.Headers.Add(HttpRequestHeader.Authorization, "GoogleLogin auth=" + authTokenString);

            Stream dataStream = request.GetRequestStream();
            dataStream.Write(byteArray, 0, byteArray.Length);
            dataStream.Close();

            WebResponse response = request.GetResponse();
            HttpStatusCode responseCode = ((HttpWebResponse)response).StatusCode;
            if (responseCode.Equals(HttpStatusCode.Unauthorized) || responseCode.Equals(HttpStatusCode.Forbidden))
            {
                Console.WriteLine("Unauthorized - need new token");
            }
            else if (!responseCode.Equals(HttpStatusCode.OK))
            {
                Console.WriteLine("Response from web service not OK :");
                Console.WriteLine(((HttpWebResponse)response).StatusDescription);
            }

            StreamReader reader = new StreamReader(response.GetResponseStream());
            string responseLine = reader.ReadLine();
            reader.Close();
        }

        private static string GetPostStringFrom(NameValueCollection nameValuePair)
        {
            StringBuilder postString = new StringBuilder();
            for (int i = 0; i < nameValuePair.Count; i++)
            {
                postString.Append(nameValuePair.GetKey(i));
                postString.Append("=");
                postString.Append(Uri.EscapeDataString(nameValuePair[i]));
                if (i + 1 != nameValuePair.Count)
                {
                    postString.Append("&");
                }
            }
            return postString.ToString();
        }

        private static string ParseForAuthTokenKey(string webResponse)
        {
            string tokenKey = String.Empty;
            if (webResponse.Contains(AuthTokenHeader))
            {
                tokenKey = webResponse.Substring(webResponse.IndexOf(AuthTokenHeader) + AuthTokenHeader.Length);
                if (tokenKey.Contains(Environment.NewLine))
                {
                    tokenKey.Substring(0, tokenKey.IndexOf(Environment.NewLine));
                }
            }
            return tokenKey.Trim();
        }

        public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            // Return "true" to force the certificate to be accepted.
            return true;
        }
    }
}
